/* eslint-disable */
import type {
  AxiosError,
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import axios from 'axios'
import { db } from '@/api/storage'

export enum ErrorCode {
  OK = 0,
  Canceled = 1,
  Unknown = 2,
}

export interface ResponseModel<T = any, CE = number> {
  code: ErrorCode | CE
  message: string
  data: T
}

interface RequestConfig extends InternalAxiosRequestConfig {
  metadata?: Record<string, unknown>
}

export class HTTPClient {
  client: AxiosInstance
  constructor() {
    this.client = axios.create({
      baseURL: import.meta.env.VITE_HOST,
      timeout: 15000, // 15s
    })

    this.client.interceptors.request.use(
      (cfg: InternalAxiosRequestConfig): RequestConfig => {
        return this.onRequest(cfg)
      },
      (error: AxiosError) => {
        console.log('requestError: ', error)
        return Promise.reject(error)
      },
    )
    this.client.interceptors.response.use(
      (rsp: AxiosResponse): AxiosResponse | Promise<AxiosResponse> => {
        return this.onResponse(rsp)
      },
      (err: AxiosError) => {
        console.log('responseError: ', err)
        return Promise.reject(err)
      },
    )
  }

  onRequest(config: InternalAxiosRequestConfig): RequestConfig {
    const token = db.GetAccessToken()
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`
    }
    return config
  }

  onResponse<RSP = any, REQ = any>(
    response: AxiosResponse<ResponseModel<RSP>, REQ>,
  ):
    | AxiosResponse<ResponseModel<RSP>>
    | Promise<AxiosResponse<AxiosResponse<ResponseModel<RSP>, REQ>>> {
    const { data } = response
    const { code } = data
    if (code === undefined) return Promise.reject(new Error('Error! code missing'))
    return response
  }

  request<RSP = any, REQ = any>(config: AxiosRequestConfig<REQ>): Promise<ResponseModel<RSP>> {
    return new Promise((resolve, reject) => {
      try {
        this.client
          .request<ResponseModel<RSP>>(config)
          .then((rsp: AxiosResponse<ResponseModel<RSP>, REQ>) => {
            resolve(rsp.data)
          })
          .catch((err) => {
            reject(err)
          })
      } catch (err) {
        return Promise.reject(err)
      }
    })
  }

  get<T = any>(config: AxiosRequestConfig): Promise<ResponseModel<T>> {
    return this.request({ method: 'GET', ...config })
  }

  post<T = any>(config: AxiosRequestConfig): Promise<ResponseModel<T>> {
    return this.request({ method: 'POST', ...config })
  }

  put<T = any>(config: AxiosRequestConfig): Promise<ResponseModel<T>> {
    return this.request({ method: 'PUT', ...config })
  }

  delete<T = any>(config: AxiosRequestConfig): Promise<ResponseModel<T>> {
    return this.request({ method: 'DELETE', ...config })
  }
}

const client = new HTTPClient()
export default client
